/*
  为了避免异步回调地狱，CommonJS社区提出了Promise的规范
  Promise是一个对象，用来表述一个异步任务执行之后是成功还是失败
  任务状态确定后不可以再次更改，pending => fulfilled || pending => rejected

  promise对象then方法，返回了全新的promise对象。可以再继续调用then方法，如果return的不是promise对象，而是一个值，那么这个值会作为resolve的值传递，如果没有值，默认是undefined
  后面的then方法就是在为上一个then返回的Promise注册回调
  前面then方法中回调函数的返回值会作为后面then方法回调的参数
  如果回调中返回的是Promise，那后面then方法的回调会等待它的结束

  Promise静态方法：Promise.resolve()，Promise.reject()
  Promise.all()和Promise.race()，接收一个数组，all等待所有任务结束，race只等待第一个任务结束
*/

/*
  微任务和宏任务
  浏览器宏任务：setTimeout，setInterval，requestAnimationFrame
  浏览器微任务：MutationObserver，Promise.then catch finally
  Node宏任务：setTimeout，setInterval，setImmediate
  Node微任务：process.nextTick，Promise.then catch finally

  promise的构造函数是同步执行，promise.then中的函数是异步执行
*/

// 1-7-6-8-2-4-9-11-3-10-5-12
//主线程直接执行
console.log('1');
//丢到宏事件队列中
setTimeout(function() {
    console.log('2');
    // process.nextTick(function() {
    //     console.log('3');
    // })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
//微事件1
// process.nextTick(function() {
//     console.log('6');
// })
//主线程直接执行
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    //微事件2
    console.log('8')
})
//丢到宏事件队列中
setTimeout(function() {
    console.log('9');
    // process.nextTick(function() {
    //     console.log('10');
    // })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})


// 使用promise封装ajax
function ajax(url) {
  return new Promise(function (resolve, reject) {
    const xhr = new XMLHttpRequest()
    xhr.open('GET', url)
    xhr.responseType = 'json'
    xhr.onload = function () {
      if (this.status === 200) {
        resolve(this.response)
      } else {
        reject(new Error(this.statusText))
      }
    }
    xhr.send()
  })
}

// ajax('/api/user.json')
//   .then(res => {
//     console.log(res)
//   })
//   .catch(err => {
//     console.log(err)
//   })

// catch等同于
// ajax('/api/user.json')
//   .then(res => {
//     console.log(res)
//   })
//   .then(undefined, err => {
//     console.log(err)
//   })
// .catch()是对上一个.then()返回的promise进行处理，不过第一个promise的报错也顺延到了catch中，而then的第二个参数形式，只能捕获第一个promise的报错，如果当前then的resolve函数处理中有报错是捕获不到的
// 所以.catch是给整个promise链条注册的一个失败回调。推荐使用！！！！

// 全局对象上的unhandledrejection事件
// 浏览器
// window.addEventListener('unhandledrejection', event => {
//   const { reason, promise } = event
//   console.log(reason, promise)

//   //reason => Promise 失败原因，一般是一个错误对象
//   //promise => 出现异常的Promise对象

//   event.preventDefault()
// }, false)

// // node
// process.on('unhandledRejection', (reason, promise) => {
//   console.log(reason, promise)

//   //reason => Promise 失败原因，一般是一个错误对象
//   //promise => 出现异常的Promise对象
// })